﻿/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.Common;
using System.Threading;
using System.Diagnostics;

namespace IvyOrm.Test.General
{
    [TestClass]
    [DeploymentItem("x86")] //SQLite
    public class GetFactoryExtensionTest
    {
        [TestMethod]
        public void GetFactory_Exeptions()
        {
            try
            {
                GetFactoryExtension.GetFactory(null);
                Assert.Fail();
            }
            catch (ArgumentException)
            { }

            try
            {
                GetFactoryExtension.GetFactory(new NoFactory.ExampleConnection());
                Assert.Fail();
            }
            catch (NotSupportedException)
            { }

            try
            {
                GetFactoryExtension.GetFactory(new MultipleFactories.ExampleConnection());
                Assert.Fail();
            }
            catch (NotSupportedException)
            { }

            try
            {
                GetFactoryExtension.GetFactory(new NullInstance.ExampleConnection());
                Assert.Fail();
            }
            catch (NotSupportedException)
            { }

        }

        [TestMethod]
        [TestCategory("No Database")]
        public void GetFactory_Cached_Multithread()
        {
            var connection = new FactoryCacheMultithread.ExampleConnection();
            var getFactoryCacheFieldInfo = typeof(GetFactoryExtension).GetField("getFactoryCache", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
            Dictionary<Type, DbProviderFactory> cache = getFactoryCacheFieldInfo.GetValue(null) as Dictionary<Type, DbProviderFactory>;
            Debug.Assert(cache != null);

            DbProviderFactory resultantFactory = null;
            DbProviderFactory targetFactory = new FactoryCacheMultithread.ExampleFactory();
            Thread t = new Thread(new ThreadStart(() =>
                {
                    resultantFactory = connection.GetFactory();
                }));

            lock (cache)
            {
                t.Start();
                Thread.Sleep(25);
                cache.Add(typeof(FactoryCacheMultithread.ExampleConnection), targetFactory);
                Assert.IsFalse(t.Join(100));
            }

            t.Join();
            Assert.AreEqual(resultantFactory, targetFactory);
        }

        [TestMethod]
        public void GetFactory_Cached()
        {
            var connection = new FactoryCache.ExampleConnection();

            Assert.AreEqual(FactoryCache.ExampleFactory.Instance, connection.GetFactory());
            Assert.AreEqual(FactoryCache.ExampleFactory.Instance, connection.GetFactory());
        }

    }
}

namespace IvyOrm.Test.FactoryCacheMultithread
{
    [System.ComponentModel.DesignerCategory("")]
    public class ExampleConnection : DbConnection
    {
        protected override DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel)
        {
            throw new NotImplementedException();
        }
        public override void ChangeDatabase(string databaseName)
        {
            throw new NotImplementedException();
        }
        public override void Close()
        {
            throw new NotImplementedException();
        }

        public override string ConnectionString { get; set; }

        protected override DbCommand CreateDbCommand()
        {
            throw new NotImplementedException();
        }

        public override string DataSource
        {
            get { throw new NotImplementedException(); }
        }

        public override string Database
        {
            get { throw new NotImplementedException(); }
        }

        public override void Open()
        {
            throw new NotImplementedException();
        }

        public override string ServerVersion
        {
            get { throw new NotImplementedException(); }
        }

        public override System.Data.ConnectionState State
        {
            get { throw new NotImplementedException(); }
        }
    }

    [System.ComponentModel.DesignerCategory("")]
    public class ExampleFactory : DbProviderFactory
    {
        public static ExampleFactory Instance = new ExampleFactory();
    }
}

namespace IvyOrm.Test.FactoryCache
{
    [System.ComponentModel.DesignerCategory("")]
    public class ExampleConnection : DbConnection
    {
        protected override DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel)
        {
            throw new NotImplementedException();
        }
        public override void ChangeDatabase(string databaseName)
        {
            throw new NotImplementedException();
        }
        public override void Close()
        {
            throw new NotImplementedException();
        }

        public override string ConnectionString { get; set; }

        protected override DbCommand CreateDbCommand()
        {
            throw new NotImplementedException();
        }

        public override string DataSource
        {
            get { throw new NotImplementedException(); }
        }

        public override string Database
        {
            get { throw new NotImplementedException(); }
        }

        public override void Open()
        {
            throw new NotImplementedException();
        }

        public override string ServerVersion
        {
            get { throw new NotImplementedException(); }
        }

        public override System.Data.ConnectionState State
        {
            get { throw new NotImplementedException(); }
        }
    }

    [System.ComponentModel.DesignerCategory("")]
    public class ExampleFactory : DbProviderFactory
    {
        public static ExampleFactory Instance = new ExampleFactory();
    }
}

namespace IvyOrm.Test.NoFactory
{
    [System.ComponentModel.DesignerCategory("")]
    class ExampleConnection : DbConnection
    {
        protected override DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel)
        {
            throw new NotImplementedException();
        }
        public override void ChangeDatabase(string databaseName)
        {
            throw new NotImplementedException();
        }
        public override void Close()
        {
            throw new NotImplementedException();
        }

        public override string ConnectionString { get; set; }

        protected override DbCommand CreateDbCommand()
        {
            throw new NotImplementedException();
        }

        public override string DataSource
        {
            get { throw new NotImplementedException(); }
        }

        public override string Database
        {
            get { throw new NotImplementedException(); }
        }

        public override void Open()
        {
            throw new NotImplementedException();
        }

        public override string ServerVersion
        {
            get { throw new NotImplementedException(); }
        }

        public override System.Data.ConnectionState State
        {
            get { throw new NotImplementedException(); }
        }
    }
}

namespace IvyOrm.Test.MultipleFactories
{
    [System.ComponentModel.DesignerCategory("")]
    public class ExampleConnection : DbConnection
    {
        protected override DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel)
        {
            throw new NotImplementedException();
        }
        public override void ChangeDatabase(string databaseName)
        {
            throw new NotImplementedException();
        }
        public override void Close()
        {
            throw new NotImplementedException();
        }

        public override string ConnectionString { get; set; }

        protected override DbCommand CreateDbCommand()
        {
            throw new NotImplementedException();
        }

        public override string DataSource
        {
            get { throw new NotImplementedException(); }
        }

        public override string Database
        {
            get { throw new NotImplementedException(); }
        }

        public override void Open()
        {
            throw new NotImplementedException();
        }

        public override string ServerVersion
        {
            get { throw new NotImplementedException(); }
        }

        public override System.Data.ConnectionState State
        {
            get { throw new NotImplementedException(); }
        }
    }

    [System.ComponentModel.DesignerCategory("")]
    public class ExampleFactory1 : DbProviderFactory
    {
        public static ExampleFactory1 Instance = new ExampleFactory1();
    }

    [System.ComponentModel.DesignerCategory("")]
    public class ExampleFactory2 : DbProviderFactory
    {
        public static ExampleFactory2 Instance = new ExampleFactory2();
    }
}

namespace IvyOrm.Test.NullInstance
{
    [System.ComponentModel.DesignerCategory("")]
    public class ExampleConnection : DbConnection
    {
        protected override DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel)
        {
            throw new NotImplementedException();
        }
        public override void ChangeDatabase(string databaseName)
        {
            throw new NotImplementedException();
        }
        public override void Close()
        {
            throw new NotImplementedException();
        }

        public override string ConnectionString { get; set; }

        protected override DbCommand CreateDbCommand()
        {
            throw new NotImplementedException();
        }

        public override string DataSource
        {
            get { throw new NotImplementedException(); }
        }

        public override string Database
        {
            get { throw new NotImplementedException(); }
        }

        public override void Open()
        {
            throw new NotImplementedException();
        }

        public override string ServerVersion
        {
            get { throw new NotImplementedException(); }
        }

        public override System.Data.ConnectionState State
        {
            get { throw new NotImplementedException(); }
        }
    }

    [System.ComponentModel.DesignerCategory("")]
    public class ExampleFactory1 : DbProviderFactory
    {
        public static ExampleFactory1 Instance = null;
    }
}